﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using OptixDotNet;
using RayDen.Library.Components.SystemComponents;
using RayDen.Library.Core.Primitives;
using RayDen.Library.Data.Import.OBJLoader;
using RayDen.Library.Data.Xml;
using RayDen.Library.Entity.Frames;
using RayDen.Library.Entity.Interface;
using RayDen.Library.Entity.Renderer;
using RayDen.Library.Entity.SceneGraph;
using RayDen.Optix.Engine.Components;
using RayDen.Optix.Engine.Scene;
using RayDen.Optix.Engine.Scene.Builders;

namespace RayDen.Optix.Engine.Managers
{
    public class RdfManager : OptixComponent
    {
        public SceneInfo Scene;
        public OptixEngineSettings Settings;
        private FrameDescription frame;


        private SceneBuilder builder;
        private OutputSettingsInfo OutputSettings;
        private QualitySettingsInfo QualitySettings;
        private string FrameName;
        public int width;
        public int height;

        public RdfManager(Context ctx) : base(ctx)
        {
            //Scene = new SceneInfo();
        }

        public void OpenFrame(string frameName)
        {
            using (var frameFile = new FileStream(frameName, FileMode.Open, FileAccess.Read))
            {
                using (var reader = new StreamReader(frameFile))
                    frame = (FrameDescription)SerializationService.Deserialize(reader.ReadToEnd(), typeof(FrameDescription));
            }
            frame.FrameName = Path.GetFileNameWithoutExtension(frameName);
            Tracer.TraceLine("Frame [[{0}]] loaded, start setuping renderer", frame.FrameName);

            InitScene();
        }

        private void InitScene()
        {
            builder = new SceneBuilder();
            this.OutputSettings = new OutputSettingsInfo(frame);
            this.QualitySettings = new QualitySettingsInfo(frame);

            this.FrameName = frame.FrameName;
            width = frame.Get<int>("ImageWidth");
            height = frame.Get<int>("ImageHeight");

            if (!string.IsNullOrWhiteSpace(frame.WorkingDir))
                Directory.SetCurrentDirectory(frame.WorkingDir);
            /*
            foreach (var frameElement in frame.Elements.Where(frameElement => frameParsers.ContainsKey(frameElement.GetType()))) {
                frameParsers[frameElement.GetType()](frameElement);
            }*/

            if (Scene == null)
            {
                SceneGraphService svc = new SceneGraphService();
                svc.Populate(
                    //new ObjLoader(),
                    new GlobalIndexObjLoader(),
                    new MaterialLoader());

                //svc.OpenFrame(frame);
                builder = new SceneBuilder() {SGService = svc};
                builder.OptixContext = this.context;
                this.Scene = builder.OpenFrame(frame);

                /*
                this.Scene.DefaultLightGain = config.Get("LightGain", new RgbSpectrum(1.0f));
                this.Scene.MaxPathDepth = config.Get("MaxPathDepth", 10);
                this.Scene.RussianRuletteImportanceCap = config.Get("RRImportanceCap", 0.75f);
                this.Scene.MaxPaths = config.Get("PathBufferSize", 65536);
                this.Scene.ShadowRayCount = config.Get("ShadowRayCount", 1);
                this.Scene.TextureSamplingQuality = this.QualitySettings.TextureSamplingQuality;
                this.Scene.LightSamplingStrategy = this.QualitySettings.LightSamplingStrategy;
                RgbSpectrum.Gamma = true;
                

                this.scene = _builder.SceneGeo;

                var sceneBound = new AABB(scene.BoundingSphereCenter - scene.BoundingSphereRadius,
                                          scene.BoundingSphereCenter + scene.BoundingSphereRadius);
                sceneBound.Expand(1f);*/
            }

            this.Initialize();
        }

        private void Initialize()
        {
        }

        internal void OpenFrame(FrameDescription frame)
        {
            this.frame = frame;
            this.InitScene();
        }
    }
}
